/*!
    \copyright  Copyright (c) 2025 Qualcomm Technologies International, Ltd.
                All Rights Reserved.
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \file       
    \ingroup    pairing
    \brief      Pairing plugin default implementation
*/

#include <pairing_plugin_default.h>
#include <pairing_private.h>
#include <logging.h>

static void Pairing_PluginDefaultRemoteIoCapability(const CL_SM_REMOTE_IO_CAPABILITY_IND_T* ind)
{
    UNUSED(ind);
    DEBUG_LOG_VERBOSE("Pairing_PluginDefaultRemoteIoCapability");
}

static pairing_plugin_rsp_t Pairing_PluginDefaultIoCapabilityReq(const CL_SM_IO_CAPABILITY_REQ_IND_T* ind, pairing_io_capability_rsp_t *io_capability_rsp)
{
    pairingTaskData *thePairing = PairingGetTaskData();
    DEBUG_LOG_VERBOSE("Pairing_PluginDefaultIoCapabilityReq");
    
    tp_bdaddr tpaddr = ind->tpaddr;
    memset(io_capability_rsp, 0, sizeof(*io_capability_rsp));
    io_capability_rsp->io_capability = cl_sm_reject_request;
    io_capability_rsp->mitm = mitm_not_required;
    io_capability_rsp->bonding = TRUE;
    io_capability_rsp->key_distribution = KEY_DIST_NONE;
    io_capability_rsp->oob_data = oob_data_none;
    io_capability_rsp->oob_hash_c = NULL;
    io_capability_rsp->oob_rand_r = NULL;

    if(tpaddr.transport == TRANSPORT_BLE_ACL)
    {
        DEBUG_LOG_VERBOSE("Pairing_PluginDefaultIoCapabilityReq Handling BLE pairing. Addr %06x BREDR Keys Exist:%d",
                          tpaddr.taddr.addr.lap, ind->link_key_exists);

        switch (pairing_GetState(thePairing))
        {
            case PAIRING_STATE_IO_CAPS_EXCHANGED:
                /* Only accept IO caps from the AG whose IO caps accepted in
                discoverable state. Reject the IO caps from other AGs */
                if(BdaddrIsSame(&thePairing->state_machine.device_address.taddr.addr, &tpaddr.taddr.addr))
                {
                    io_capability_rsp->io_capability = cl_sm_io_cap_no_input_no_output;
                }
                break;

            case PAIRING_STATE_AWAITING_IO_CAPS_EXCHANGE:
                io_capability_rsp->io_capability = cl_sm_io_cap_no_input_no_output;
                break;

            case PAIRING_STATE_DISCOVERABLE:
            case PAIRING_STATE_IDLE:
            {
                bool random_address = (tpaddr.taddr.type == TYPED_BDADDR_RANDOM);
                bool known_address = BtDevice_isKnownBdAddr(&tpaddr.taddr.addr);

                DEBUG_LOG_VERBOSE("Pairing_PluginDefaultIoCapabilityReq. random:%d ble_permission:%d sm_over_bredr:%d known_address:%d",
                                    random_address,
                                    thePairing->state_machine.ble_permission,
                                    ind->sm_over_bredr,
                                    known_address);

                    /* BLE pairing is not allowed */
                if (thePairing->state_machine.ble_permission == pairingBleDisallowed)
                {
                    DEBUG_LOG_VERBOSE("Pairing_PluginDefaultIoCapabilityReq. BLE pairing not allowed");
                    io_capability_rsp->bonding = FALSE;
                }
                else
                {
                    io_capability_rsp->io_capability = cl_sm_io_cap_no_input_no_output;
                }
            }
            break;

        default:
            break;
        }

        io_capability_rsp->key_distribution = (KEY_DIST_RESPONDER_ENC_CENTRAL |
                                     KEY_DIST_RESPONDER_ID | KEY_DIST_INITIATOR_ENC_CENTRAL |
                                     KEY_DIST_INITIATOR_ID);
        if (ind->link_key_exists)
        {
            DEBUG_LOG("Pairing_PluginDefaultIoCapabilityReq adding extra flags");
            /* We have existing BREDR pairing for the device that is now pairing over BLE.
               If we are in a pairing state, request regeneration of the BREDR keys */
            io_capability_rsp->key_distribution |= (KEY_DIST_INITIATOR_LINK_KEY | KEY_DIST_RESPONDER_LINK_KEY);
        }
    }
    else
    {
        DEBUG_LOG_VERBOSE("Pairing_PluginDefaultIoCapabilityReq handling BREDR pairing");
        switch (pairing_GetState(thePairing))
        {
            case PAIRING_STATE_IO_CAPS_EXCHANGED:
                /* Only accept IO caps from the AG whose IO caps accepted in
                discoverable state. Reject the IO caps from other AGs */
                if(BdaddrIsSame(&thePairing->state_machine.device_address.taddr.addr, &tpaddr.taddr.addr))
                {
                    io_capability_rsp->io_capability = cl_sm_io_cap_no_input_no_output;
                }
                break;

            case PAIRING_STATE_AWAITING_IO_CAPS_EXCHANGE:
            case PAIRING_STATE_DISCOVERABLE:
                io_capability_rsp->io_capability = cl_sm_io_cap_no_input_no_output;
                break;

            default:
                break;
        }
    }
    
    return pairing_plugin_response_update;
}

static pairing_plugin_rsp_t Pairing_PluginDefaultUserConfirmation(const CL_SM_USER_CONFIRMATION_REQ_IND_T* ind, pairing_user_confirmation_rsp_t* user_confirmation_rsp)
{
    UNUSED(ind);
    DEBUG_LOG_VERBOSE("Pairing_PluginDefaultUserConfirmation");
    /* By default MITM is not supported, reject user confirmation */
    user_confirmation_rsp->accept = FALSE;
    return pairing_plugin_response_update;
}

static pairing_plugin_rsp_t Pairing_PluginDefaultCtkd(const pairing_ctkd_ind_t* ind, pairing_ctkd_rsp_t* rsp)
{
    UNUSED(ind);
    DEBUG_LOG_VERBOSE("Pairing_PluginDefaultCtkd");
    /* By default allow CTKD with all devices */
    rsp->allow_ctkd = TRUE;
    return pairing_plugin_response_update;
}

static pairing_plugin_rsp_t Pairing_PluginDefaultSspCompleteInd(const pairing_ssp_complete_ind_t* ind, pairing_ssp_complete_rsp_t* rsp)
{
    pairingTaskData *thePairing = PairingGetTaskData();
    DEBUG_LOG_VERBOSE("Pairing_PluginDefaultSspCompleteInd");
    
    rsp->ble_permission = thePairing->state_machine.ble_permission;

    if(ind->tpaddr.transport == TRANSPORT_BREDR_ACL)
    {
        switch (pairing_GetState(thePairing))
        {
            case PAIRING_STATE_IO_CAPS_EXCHANGED:
                if (ind->status != HCI_SUCCESS && !BdaddrIsSame(&thePairing->state_machine.device_address.taddr.addr, &ind->tpaddr.taddr.addr))
                {
                    /* Ignore failure for devices other than the one already being paired */
                    break;
                }
            /* Fall through */
            case PAIRING_STATE_AWAITING_IO_CAPS_EXCHANGE:
                if(ind->status == HCI_SUCCESS)
                {
                    if(!BtDevice_BdaddrTypedIsSame(&ind->tpaddr.taddr, &thePairing->state_machine.device_address.taddr))
                    {
                        /* Allow ble connections only with paired device after BR/EDR pairing. */
                        rsp->ble_permission = pairingBleOnlyPairedDevices;
                    }
                }
                else
                {
                    rsp->ble_permission = pairingBleDisallowed;
                }
            break;
            
            default:
            break;
        }
    }
    
    return pairing_plugin_response_update;
}


pairing_plugin_t pairing_plugin_default = 
{
    .handle_remote_io_capability = Pairing_PluginDefaultRemoteIoCapability,
    .handle_io_capability_req = Pairing_PluginDefaultIoCapabilityReq,
    .handle_user_confirmation_req = Pairing_PluginDefaultUserConfirmation,
    .handle_ctkd = Pairing_PluginDefaultCtkd,
    .handle_ssp_complete_indication = Pairing_PluginDefaultSspCompleteInd,
};
